package com.garlic.face.jlf.transaction;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.garlic.face.jlf.App;
import com.garlic.face.jlf.R;
import com.garlic.face.jlf.utils.LogUtils;
import com.garlic.face.jlf.utils.ToastUtils;
import com.garlic.face.jlf.utils.Tools;

import org.greenrobot.eventbus.EventBus;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import es.dmoral.toasty.Toasty;


public class SocketService extends Service {

    private static final String TAG = "SocketService";
    //心跳包频率
    private static final long HEART_BEAT_RATE = 10 * 1000;

    public static String HOST = "";// 服务端IP地址
    //public static final String HOST = "10.132.255.172";// 服务端IP地址
    public static int PORT = -1;
    public static final String HEART_BEAT_STRING = "";//心跳包内容
    private ReadThread mReadThread;
    private WeakReference<Socket> mSocket;
    private long sendTime;
    private Handler mHandler = new Handler();
    private boolean isSuccess;//标识长连接是否成功
    private boolean isInitStart = true;//是否停止初始化

    private boolean isLastSendMsgSuccess = true;//上次发送消息成功
    public static final String BACK_TO_MAIN = "back_to_main";
    private Dialog mDialog = null;
    private boolean mDialogIsShowing = false;

    public SocketService() {
        Log.d(TAG, "SocketService: 构造OK");
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new ServiceBinder();
    }

    public SocketService getService() {
        return SocketService.this;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        initService();
        LogUtils.d("xxxx 启动sockt service oncreate", true);
    }

    public void initService() {
        HOST = (String) Tools.getPref(App.CONFIG_INFO, App.POS_IP, "");
        PORT = (int) Tools.getPref(App.CONFIG_INFO, App.POS_PORT, 0);
        LogUtils.d("xxxxxx 启动初始化service ip:" + HOST + " port:" + PORT, true);
        if(!TextUtils.isEmpty(HOST)){
            sendTime = System.currentTimeMillis();
            new InitSocketThread().start();
        }
    }


    // 初始化socketThread
    class InitSocketThread extends Thread {

        @Override
        public void run() {
            super.run();
            initSocket();
        }
    }

    private void initSocket() { // 初始化Socket
        try {
            if(!isInitStart){
                return;
            }

            //App崩溃后重新回到主页会重新绑定服务，或者用户手动点击配置也会重新绑定服务
            //此时应该释放之前的socket，连接新的service todo 待测
            if(mSocket != null){
                LogUtils.d("xxxxxx 释放之前的socket", true);
                mHandler.removeCallbacks(heartBeatRunnable);
                mReadThread.release();
                releaseLastSocket(mSocket);
            }

            Socket so = new Socket(HOST, PORT);
            LogUtils.d("xxxx initSocket so: " + so, true);

            mSocket = new WeakReference<Socket>(so);
            mReadThread = new ReadThread(so);
            mReadThread.start();
            mHandler.postDelayed(heartBeatRunnable, HEART_BEAT_RATE);//初始化成功后，就准备发送心跳包
            LogUtils.d("xxxxx send state login "+isLastSendMsgSuccess, true);
            if(!isLastSendMsgSuccess & sendMsg(CarrfourUtil.getInstance().getStateInfo())){
                LogUtils.d("xxxxx 上次失败，本次成功，回退到主页", true);
                ToastUtils.toastShow("请重新开始交易", ToastUtils.SUCCESS);
                if(mDialog != null){
                    mDialog.dismiss();
                    mDialogIsShowing = false;
                }
                EventBus.getDefault().post(BACK_TO_MAIN);
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
            LogUtils.e("xxxx UnknownHostException: " + HOST + " " + PORT + " msg:" + e.getMessage() + " " + e.getLocalizedMessage());
            new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    ToastUtils.toastShow("未知主机，请检查主机IP和端口", ToastUtils.ERROR);
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
            LogUtils.e("xxxx IOException ip:" + HOST + " port:" + PORT + " msg:" + e.getMessage() + " " + e.getLocalizedMessage());
            //初始化出错，是否重新初始化
            if (!TextUtils.isEmpty(HOST)) {
                String msg = e.getMessage();
                if (!TextUtils.isEmpty(msg) && msg.contains("Connection refused")) {
                    new Handler(Looper.getMainLooper()).post(new Runnable() {
                        @Override
                        public void run() {
                            //ToastUtils.toastShow("服务器异常，请联系工作人员重启POS机", ToastUtils.ERROR);
                            Toasty.error(App.getContext(), "服务器异常，请联系工作人员重启POS机", Toast.LENGTH_LONG).show();
                            if(App.getActivityStack() != null && App.getActivityStack().size() > 0 && !mDialogIsShowing){
                                mDialog = new AlertDialog.Builder(App.getActivityStack().get(App.getActivityStack().size() - 1))
                                        .setTitle("错误").setMessage("服务器异常，请联系工作人员重启POS机").setCancelable(true).create();
                                mDialog.show();
                                mDialogIsShowing = true;
                            }
                            App.playSound(getResources().getString(R.string.sound_no_network));
                        }
                    });
                    //连接被拒，等待1分钟后继续尝试初始化 todo 待测

                }else if(!TextUtils.isEmpty(msg) && msg.contains("No route")){
                    new Handler(Looper.getMainLooper()).post(new Runnable() {
                        @Override
                        public void run() {
                            Toasty.error(App.getContext(), "连接失败，请检查网络是否正常", Toast.LENGTH_LONG).show();
                            App.playSound(getResources().getString(R.string.sound_no_network));
                        }
                    });
                }else if(!TextUtils.isEmpty(msg) && msg.contains("timed out")){
                    new Handler(Looper.getMainLooper()).post(new Runnable() {
                        @Override
                        public void run() {
                            Toasty.error(App.getContext(), "连接超时，请检查网络是否正常", Toast.LENGTH_LONG).show();
                            App.playSound(getResources().getString(R.string.sound_no_network));
                        }
                    });
                }
                try {
                    Thread.sleep(1000*20);//重新初始化连接
                    initSocket();
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }

            }
        }
    }

    /**
     * 发送心跳包
     */
    private Runnable heartBeatRunnable = new Runnable() {

        @Override
        public void run() {
            if (System.currentTimeMillis() - sendTime >= HEART_BEAT_RATE) {
                boolean isSuccess = sendMsg(HEART_BEAT_STRING);//就发送一个HEART_BEAT_STRING过去 如果发送失败，就重新初始化一个socket
                LogUtils.d("xxxx 发送心跳包成功: " + isSuccess, false);
                if (!isSuccess) {
                    isLastSendMsgSuccess = false;
                    mHandler.removeCallbacks(heartBeatRunnable);
                    mReadThread.release();
                    releaseLastSocket(mSocket);
                    new InitSocketThread().start();
                }else{
                    mHandler.postDelayed(this, HEART_BEAT_RATE);
                }
            }else{
                mHandler.postDelayed(this, HEART_BEAT_RATE);
            }

        }
    };

    public boolean sendMsg(String msg) {
        if (null == mSocket || null == mSocket.get()) {
            LogUtils.e("xxxxx socket is null");
           /* new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    Toasty.error(App.getContext(), "连接服务器异常，请检查POS机", Toast.LENGTH_LONG).show();
                }
            });*/
            return false;
        }
        Socket soc = mSocket.get();
        try {
            if (!soc.isClosed() && !soc.isOutputShutdown()) {
                OutputStream os = soc.getOutputStream();
                String message = msg;
                os.write(message.getBytes());
                os.flush();
                sendTime = System.currentTimeMillis();//每次发送成数据，就改一下最后成功发送的时间，节省心跳间隔时间
                LogUtils.d("xxxx 发送消息成功sendMsg: send ok msg: " + msg, false);
            } else {
                LogUtils.e("xxxx 发送消息失败sendMsg: send error msg: " + msg);
                return false;
            }
        } catch (IOException e) {
            String message = e.getMessage();
            LogUtils.e("xxxx 发送消息失败sendMsg: send error " + message);
            //每次发消息失败都重新初始化一下socket
            if(!msg.equals(HEART_BEAT_STRING)){
                isLastSendMsgSuccess = false;
                mHandler.removeCallbacks(heartBeatRunnable);
                mReadThread.release();
                releaseLastSocket(mSocket);
                new InitSocketThread().start();
                //这里立即发会不会有问题，一直立即循环
            }
            return false;
        }
        isLastSendMsgSuccess = true;
        return true;
    }

    private void releaseLastSocket(WeakReference<Socket> mSocket) {
        try {
            if (null != mSocket) {
                Socket sk = mSocket.get();
                if (sk != null && !sk.isClosed()) {
                    sk.close();
                }
                sk = null;
                mSocket = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private byte[] addBytes(byte[] data1, byte[] data2) {
        byte[] data3 = new byte[data1.length + data2.length];
        System.arraycopy(data1, 0, data3, 0, data1.length);
        System.arraycopy(data2, 0, data3, data1.length, data2.length);
        return data3;
    }

    // 获取消息Thread
    class ReadThread extends Thread {
        private WeakReference<Socket> mWeakSocket;
        private boolean isStart = true;

        public ReadThread(Socket socket) {
            mWeakSocket = new WeakReference<Socket>(socket);
        }

        public void release() {
            isStart = false;
            releaseLastSocket(mWeakSocket);
        }

        @Override
        public void run() {
            super.run();
            Socket socket = mWeakSocket.get();
            if (null != socket) {
                try {
                    InputStream is = socket.getInputStream();
                    byte[] totalbuffer = new byte[0];
                    byte[] buffer = new byte[1024*8];
                    int length = 0;
                    int totallenght = 0;
                    while (!socket.isClosed() && !socket.isInputShutdown()
                            && isStart && ((length = is.read(buffer, 0, buffer.length)) != -1)) {
                        LogUtils.d("socket length" + length, true);
                        if (length > 0) {
                            totallenght += length;
                            LogUtils.d("socket totallength" + totallenght, true);
                            totalbuffer = addBytes(totalbuffer, Arrays.copyOf(buffer, length));
                            String message = new String(Arrays.copyOf(totalbuffer,
                                    totallenght)).trim();
//                            String message = new String(totalbuffer);
                            LogUtils.d(message, true);
                            //recvBytes.add(buffer);
                            //String str = new String(buffer, "utf-8");
                            //比较"}"和"{"的数量，数量一致表示接收完毕
                            //leftCount += pattern(str, "{");
                            //rightCount += pattern(str, "}");
                            //if(leftCount == rightCount)
                            //break;
                            //收到服务器过来的消息
                            if (message.equals(HEART_BEAT_STRING)) {//处理心跳回复

//                                Intent intent=new Intent(HEART_BEAT_ACTION);
//                                mLocalBroadcastManager.sendBroadcast(intent);
                            } else {
                                // TODO: 2018/7/11 传递回去
                                try {
                                    JSONObject jsonObject = new JSONObject(message);
                                    LogUtils.d("-----json format" +  jsonObject.toString(), true);
                                    EventBus.getDefault().post(jsonObject);
                                    totalbuffer = new byte[0];
                                    totallenght = 0;
                                } catch (JSONException e) {
                                    e.printStackTrace();
                                    LogUtils.e("SocketService recv:" + message + e.getMessage());
                                    continue;
                                }finally {
                                    buffer = new byte[1024*8];
                                }
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private int pattern(String text, String matchStr) {
        Pattern pattern = Pattern.compile(matchStr);
        Matcher matcher = pattern.matcher(text);
        int count = 0;
        while (matcher.find()) {
            count++;
        }
        return count;
    }

    public class ServiceBinder extends Binder {
        public SocketService getService() {
            return SocketService.this;
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        isInitStart = false;
        if(mSocket != null){
            mHandler.removeCallbacks(heartBeatRunnable);
            mReadThread.release();
            releaseLastSocket(mSocket);
        }
    }

    public boolean isSocketNull(){
        if (null == mSocket || null == mSocket.get()) {
            LogUtils.d("xxxxx socket is null", true);
            return true;
        }
        return false;
    }


    public void releaseSocket(){
        LogUtils.d("-----" + "releaseSocket", true);
        if(mSocket != null){
            mHandler.removeCallbacks(heartBeatRunnable);
            mReadThread.release();
            releaseLastSocket(mSocket);
        }
    }

}
